<?php
class Bliss_Model
{
	/**
	 * The table row
	 *
	 * @var Zend_Db_Table_Row
	 */
	protected $_row;

	/**
	 * The model's data
	 *
	 * @var Zend_Config
	 */
	protected $_data;

	/**
	 * The database table's model
	 *
	 * @var Zend_Db_Table_Abstract
	 */
	protected $_table;

	/**
	 * The name of the table's model
	 *
	 * @var string
	 */
	protected $_tableModel;

	/**
	 * Custom query to use in place of the default one.
	 *
	 * @var Zend_Db_Select
	 */
	protected $_query;

	/**
	 * Constructor
	 *
	 * @param mixed $params
	 * @param Zend_Db_Table_Abstract $table
	 */
	public function __construct($params = null, Zend_Db_Table_Abstract $table = null)
	{
		$this->_data		= new Zend_Config(array(), true);
		if($params instanceOf Zend_Db_Table_Row) {
			$this->setRow($params);
		} elseif(is_array($params)) {
			$this->setData($params);
		}

		$this->_tableModel == isset($table) ? $table : $this->_tableModel;
		if(isset($this->_tableModel)) {
			$this->setTableModel($this->_tableModel);
		}
	}

	public function setTableModel($name)
	{
		$this->_table = $name instanceOf Zend_Db_Table_Abstract ? $name : new $name();
	}

	public function setQuery(Zend_Db_Select $query)
	{
		$this->_query = $query;
	}

	public function get(array $data = null)
	{
		if(isset($this->_row)) {
			return $this->_row;
		}

		if(!isset($this->_table)) {
			throw new Zend_Exception("No table model has been provided.");
		}

		if(isset($data)) {
			$this->setData($data);
		}

		if(!count($this->_data)) {
			return null;
		}

		$query	= isset($this->_query) ? $this->_query : $this->_table->select();
		foreach($this->_data as $key => $value) {
			if(!isset($value))	$value = '';
			$query->where("{$key}=?", $value);
		}
		$row	= $this->_table->fetchRow($query);

		if(isset($row)) {
			$this->setRow($row);
			return $this->getRow();
		}
	}

	public function setData(array $data, $setRow = false)
	{
		$this->_data = new Zend_Config($data, true);
		if(isset($this->_row) && $setRow !== false) {
			foreach($data as $k => $v) {
				$this->_row->{$k} = $v;
			}
		}
		return $this;
	}

	/**
	 * Sets the table row for this model.
	 *
	 * @param Zend_Db_Table_Row $row
	 */
	public function setRow(Zend_Db_Table_Row $row = null)
	{
		$this->_row	= $row;
		$this->setData($row->toArray());
	}

	/**
	 * Gets the table row for this model.
	 *
	 * @return <type>
	 */
	public function getRow()
	{
		return $this->_row;
	}

	/**
	 * Returns a field from the table's row
	 *
	 * @param string $name
	 * @return string
	 */
	public function __get($name)
	{

		if(!isset($this->_data->{$name})) {
			$this->get();
		}
		
		return isset($this->_data->{$name}) ? $this->_data->{$name} : null;
	}

	/**
	 * Sets a field in the table's row
	 *
	 * @param string $name
	 * @param string $value
	 */
	public function __set($name, $value)
	{
		$this->_data->{$name}	= $value;
	}

	/**
	 * Checks if a field in the table's row exists.
	 *
	 * @param string $name
	 * @return bool
	 */
	public function __isset($name)
	{
		return isset($this->_data->{$name});
	}

	/**
	 * Checks if the table row exists
	 *
	 * @return bool
	 */
	public function exists()
	{
		$this->get();
		return isset($this->_row);
	}

	/**
	 * Deletes the current row.
	 *
	 * @return int The number of records affected
	 */
	public function delete()
	{
		if($this->exists()) {
			return $this->_row->delete();
		}
	}

	/**
	 * Updates or inserts the current data.
	 *
	 * @param bool $new
	 * @return bool
	 */
	public function save($new=false)
	{
		if($new !== false || !isset($this->_row)) {
			return $this->getTable()->insert($this->_data->toArray());
		} elseif($this->exists()) {
			return $this->_row->save();
		}
	}

	/**
	 * Gets the database table model
	 *
	 * @return Zend_Db_Table_Abstract
	 */
	public function getTable()
	{
		return $this->_table;
	}

	/**
	 * Returns the row as an array
	 *
	 * return array
	 */
	public function toArray()
	{
		return isset($this->_row) ? $this->_row->toArray() : array();
	}

	/**
	 * Gets many records from the specified table using
	 * the given rows.
	 *
	 * @example
	 *	$model->getMany('comments', array(
	 *		'parent_id'		=> $model->id,
	 *		'parent_type'	=> 'news'
	 *	));
	 *
	 * @param mixed $table Either the name of a table or instance of Zend_Db_Table_Abstract
	 * @param array $params Array of columns to look up on
	 * @param string $order
	 * @param string $limit
	 * @return array
	 */
	public function getMany($table, array $params = null, $order = null, $limit = null)
	{
		if($table instanceOf Zend_Db_Table_Abstract) {
			$db		= $table;
			$query	= $table->select();
		} else {
			$db		= $this->_table->getAdapter();
			$query	= $db->select()->from($table);
		}
		
		if(isset($order)) $query->order($order);
		if(isset($limit)) $query->limit($limit);
		if(isset($params)) {
			foreach($params as $field => $value)
			{
				$query->where("{$field}=?", $value);
			}
		}
		
		$results	= $db->fetchAll($query);
		return $results;
	}

	/**
	 * Gets one record
	 * @see self::getMany
	 *
	 * @param string $table
	 * @param array $params
	 * @param string $order
	 * @return array
	 */
	public function getOne($table, array $params = null, $order = null)
	{
		$results	= (array) $this->getMany($table, $params, $order, 1);
		return array_shift($results);
	}
}
?>